#include <wx/wx.h>
#include "panel_distortion.h"
#include "MyCommon.h"
#include "DataSave.h"


#define SLI_MAX(max,min,step) (int)((max - min) / step)


wxDEFINE_EVENT(myEVT_DISTORTION, MyEventDistortion);
wxDEFINE_EVENT(myEVT_DISTORTION_TONE, MyEventDistortion);
wxDEFINE_EVENT(myEVT_DISTORTION_LEVEL, MyEventDistortion);
wxDEFINE_EVENT(myEVT_DISTORTION_DRIVE, MyEventDistortion);
wxDEFINE_EVENT(myEVT_DISTORTION_GAIN, MyEventDistortion);
wxDEFINE_EVENT(myEVT_DISTORTION_ENABLE, MyEventDistortion);
wxDEFINE_EVENT(myEVT_DISTORTION_FREQ, MyEventDistortion);
wxDEFINE_EVENT(myEVT_DISTORTION_WIDTH, MyEventDistortion);
wxDEFINE_EVENT(myEVT_DISTORTION_EQ, MyEventDistortion);

wxDECLARE_EVENT(myEVT_EQUALIZER, MyEventEqualizer);
wxDECLARE_EVENT(myEVT_EQUALIZER_FREQUENCY, MyEventEqualizer);
wxDECLARE_EVENT(myEVT_EQUALIZER_GAIN, MyEventEqualizer);
wxDECLARE_EVENT(myEVT_EQUALIZER_QFACTOR, MyEventEqualizer);
wxDECLARE_EVENT(myEVT_EQUALIZER_TYPE, MyEventEqualizer);


PanelDistortion::PanelDistortion(const wxString &title, wxXmlNode *node, wxWindowID id, wxWindow *parent)
    : wxPanel(parent,id,wxDefaultPosition,wxDefaultSize,wxTAB_TRAVERSAL)
{
    this_id = id;
    SetSize(200, 300);

    root_node = node;
    select_index = 0;
    // wxArrayString items;
    // items.clear();
    int cid = this_id+1;
    ID_TXT_TONE = cid ++;
    ID_TXT_LEVEL = cid ++;
    ID_TXT_DRIVE = cid ++;
    ID_TXT_GAIN = cid ++;
    ID_TXT_FREQ = cid ++;
    ID_TXT_WIDTH = cid ++;
    ID_SLI_TONE = cid ++;
    ID_SLI_LEVEL = cid ++;
    ID_SLI_DRIVE = cid ++;
    ID_SLI_GAIN = cid ++;
    ID_SLI_FREQ = cid ++;
    ID_SLI_WIDTH = cid ++;
    ID_CHO_PRESET = cid ++;
    ID_CHK_SWITCH = cid ++;
    ID_BTN_EQ = cid ++;

    // equalizer = new GraphicEqualizer(nullptr, wxID_ANY, "Graphic EQ",wxDefaultPosition,wxSize(100,100));
    // equalizer->SetSampleRate(48000);

    wxCheckBox   *chk_enable    = new wxCheckBox(this,   ID_CHK_SWITCH, "Enable");
    wxTextCtrl   *txt_tone      = new wxTextCtrl(this,   ID_TXT_TONE,   mDoubleToString(tone_min),      wxDefaultPosition, wxDefaultSize,         wxTE_PROCESS_ENTER);
    wxTextCtrl   *txt_outgain   = new wxTextCtrl(this,   ID_TXT_LEVEL,  mDoubleToString(outgain_min),   wxDefaultPosition, wxDefaultSize,         wxTE_PROCESS_ENTER);
    wxTextCtrl   *txt_drive     = new wxTextCtrl(this,   ID_TXT_DRIVE,  mDoubleToString(drive_min),     wxDefaultPosition, wxDefaultSize,         wxTE_PROCESS_ENTER);
    wxTextCtrl   *txt_gain      = new wxTextCtrl(this,   ID_TXT_GAIN,   mDoubleToString(gain_min),      wxDefaultPosition, wxDefaultSize,         wxTE_PROCESS_ENTER);
    wxTextCtrl   *txt_freq      = new wxTextCtrl(this,   ID_TXT_FREQ,   mDoubleToString(freq_min),      wxDefaultPosition, wxDefaultSize,         wxTE_PROCESS_ENTER);
    wxTextCtrl   *txt_bandwidth = new wxTextCtrl(this,   ID_TXT_WIDTH,  mDoubleToString(bandwidth_min), wxDefaultPosition, wxDefaultSize,         wxTE_PROCESS_ENTER);
    wxStaticText *lab_tone      = new wxStaticText(this, wxID_ANY,      "Tone:");
    wxStaticText *lab_outgain   = new wxStaticText(this, wxID_ANY,      "Level:");
    wxStaticText *lab_drive     = new wxStaticText(this, wxID_ANY,      "Drive:");
    wxStaticText *lab_gain      = new wxStaticText(this, wxID_ANY,      "Gain:");
    wxStaticText *lab_freq      = new wxStaticText(this, wxID_ANY,      "Freq:");
    wxStaticText *lab_bandwidth = new wxStaticText(this, wxID_ANY,      "Width:");
    wxStaticText *lab_preset    = new wxStaticText(this, wxID_ANY,      "Preset:");
    wxSlider     *sli_tone      = new wxSlider(this,     ID_SLI_TONE,   0,                              0,                 SLI_MAX(tone_max,      tone_min,            tone_step));
    wxSlider     *sli_outgain   = new wxSlider(this,     ID_SLI_LEVEL,  0,                              0,                 SLI_MAX(outgain_max,   outgain_min,         outgain_step));
    wxSlider     *sli_drive     = new wxSlider(this,     ID_SLI_DRIVE,  0,                              0,                 SLI_MAX(drive_max,     drive_min,           drive_step));
    wxSlider     *sli_gain      = new wxSlider(this,     ID_SLI_GAIN,   0,                              0,                 SLI_MAX(gain_max,      gain_min,            gain_step));
    wxSlider     *sli_freq      = new wxSlider(this,     ID_SLI_FREQ,   0,                              0,                 SLI_MAX(freq_max,      freq_min,            freq_step));
    wxSlider     *sli_bandwidth = new wxSlider(this,     ID_SLI_WIDTH,  0,                              0,                 SLI_MAX(bandwidth_max, bandwidth_min,       bandwidth_step));
    wxChoice        *cho_preset      = new wxChoice(this,     ID_CHO_PRESET);
    wxFlexGridSizer *layout_main = new wxFlexGridSizer(9, 3,             wxSize(3,                   3));
    wxButton *btn_eq = new wxButton(this, ID_BTN_EQ, "EQ");

    sli_tone->SetMinSize(wxSize(100, -1));
    sli_tone->SetTick(1);
    sli_outgain->SetMinSize(wxSize(100, -1));
    sli_drive->SetMinSize(wxSize(100, -1));
    sli_gain->SetMinSize(wxSize(100, -1));
    txt_tone->SetMinSize(wxSize(50, -1));
    txt_tone->SetMaxSize(wxSize(100, -1));
    txt_outgain->SetMinSize(wxSize(50, -1));
    txt_outgain->SetMaxSize(wxSize(100, -1));
    txt_drive->SetMinSize(wxSize(50, -1));
    txt_drive->SetMaxSize(wxSize(100, -1));
    txt_gain->SetMinSize(wxSize(50, -1));
    txt_gain->SetMaxSize(wxSize(100, -1));
    txt_freq->SetMinSize(wxSize(50, -1));
    txt_freq->SetMaxSize(wxSize(100, -1));
    txt_bandwidth->SetMinSize(wxSize(50, -1));
    txt_bandwidth->SetMaxSize(wxSize(100, -1));

    sli_bandwidth->Bind(wxEVT_SLIDER, &PanelDistortion::OnSliderChange, this, ID_SLI_WIDTH);
    sli_freq->Bind(wxEVT_SLIDER,      &PanelDistortion::OnSliderChange, this, ID_SLI_FREQ);
    sli_gain->Bind(wxEVT_SLIDER,      &PanelDistortion::OnSliderChange, this, ID_SLI_GAIN);
    sli_drive->Bind(wxEVT_SLIDER,     &PanelDistortion::OnSliderChange, this, ID_SLI_DRIVE);
    sli_outgain->Bind(wxEVT_SLIDER,   &PanelDistortion::OnSliderChange, this, ID_SLI_LEVEL);
    sli_tone->Bind(wxEVT_SLIDER,      &PanelDistortion::OnSliderChange, this, ID_SLI_TONE);
    txt_bandwidth->Bind(wxEVT_TEXT_ENTER,   &PanelDistortion::OnTextEnter,    this, ID_TXT_WIDTH);
    txt_freq->Bind(wxEVT_TEXT_ENTER,        &PanelDistortion::OnTextEnter,    this, ID_TXT_FREQ);
    txt_gain->Bind(wxEVT_TEXT_ENTER,        &PanelDistortion::OnTextEnter,    this, ID_TXT_GAIN);
    txt_drive->Bind(wxEVT_TEXT_ENTER,       &PanelDistortion::OnTextEnter,    this, ID_TXT_DRIVE);
    txt_outgain->Bind(wxEVT_TEXT_ENTER,     &PanelDistortion::OnTextEnter,    this, ID_TXT_LEVEL);
    txt_tone->Bind(wxEVT_TEXT_ENTER,        &PanelDistortion::OnTextEnter,    this, ID_TXT_TONE);
    chk_enable->Bind(wxEVT_CHECKBOX,  &PanelDistortion::OnChkChange,    this, ID_CHK_SWITCH);
    cho_preset->Bind(wxEVT_CHOICE,        &PanelDistortion::OnCombChange,   this, ID_CHO_PRESET);
    btn_eq->Bind(wxEVT_BUTTON,        &PanelDistortion::OnBtnEq,        this, ID_BTN_EQ);

    // cho_preset->Append("distortion1-1");
    // cho_preset->Append("distortion1-2");
    // cho_preset->Append("distortion2-1");
    // cho_preset->Append("distortion2-2");
    // cho_preset->Append("distortion3-1");
    // cho_preset->Append("distortion3-2");
    // cho_preset->Append("distortion4-1");
    // cho_preset->Append("distortion4-2");
    // cho_preset->Append("distortion5-1");
    // cho_preset->Append("distortion5-2");
    // cho_preset->Append("distortion6-1");
    // cho_preset->Append("distortion6-2");
    // cho_preset->Select(select_index);

    layout_main->Add(chk_enable  ,0,wxALIGN_CENTER_VERTICAL | wxEXPAND);
    layout_main->AddStretchSpacer();
    layout_main->AddStretchSpacer();
    layout_main->Add(lab_tone     ,0,wxALIGN_CENTER_VERTICAL | wxEXPAND);
    layout_main->Add(txt_tone     ,0,wxALIGN_CENTER_VERTICAL | wxEXPAND);
    layout_main->Add(sli_tone     ,0,wxALIGN_CENTER_VERTICAL | wxEXPAND);
    layout_main->Add(lab_outgain     ,0,wxALIGN_CENTER_VERTICAL | wxEXPAND);
    layout_main->Add(txt_outgain     ,0,wxALIGN_CENTER_VERTICAL | wxEXPAND);
    layout_main->Add(sli_outgain     ,0,wxALIGN_CENTER_VERTICAL | wxEXPAND);
    layout_main->Add(lab_drive,0,wxALIGN_CENTER_VERTICAL | wxEXPAND);
    layout_main->Add(txt_drive,0,wxALIGN_CENTER_VERTICAL | wxEXPAND);
    layout_main->Add(sli_drive,0,wxALIGN_CENTER_VERTICAL | wxEXPAND);
    layout_main->Add(lab_gain    ,0,wxALIGN_CENTER_VERTICAL | wxEXPAND);
    layout_main->Add(txt_gain    ,0,wxALIGN_CENTER_VERTICAL | wxEXPAND);
    layout_main->Add(sli_gain    ,0,wxALIGN_CENTER_VERTICAL | wxEXPAND);
    layout_main->Add(lab_freq    ,0,wxALIGN_CENTER_VERTICAL | wxEXPAND);
    layout_main->Add(txt_freq    ,0,wxALIGN_CENTER_VERTICAL | wxEXPAND);
    layout_main->Add(sli_freq    ,0,wxALIGN_CENTER_VERTICAL | wxEXPAND);
    layout_main->Add(lab_bandwidth    ,0,wxALIGN_CENTER_VERTICAL | wxEXPAND);
    layout_main->Add(txt_bandwidth    ,0,wxALIGN_CENTER_VERTICAL | wxEXPAND);
    layout_main->Add(sli_bandwidth    ,0,wxALIGN_CENTER_VERTICAL | wxEXPAND);
    layout_main->Add(lab_preset,0,wxALIGN_CENTER_VERTICAL | wxEXPAND);
    layout_main->Add(cho_preset,0,wxALIGN_CENTER_VERTICAL | wxEXPAND);
    // layout_main->AddStretchSpacer();
    layout_main->Add(btn_eq,0,wxALIGN_CENTER_VERTICAL | wxEXPAND);

    layout_main->AddGrowableCol(0,0);
    layout_main->AddGrowableCol(1,0);
    layout_main->AddGrowableCol(2,1);

    SetSizer(layout_main);

    paneInfo.Caption(title);
    paneInfo.Dock();
    paneInfo.Dockable(true);
    paneInfo.CloseButton(true);
    paneInfo.MaximizeButton(true);
    paneInfo.MinimizeButton(true);
    paneInfo.DestroyOnClose(false);
    // paneInfo.Direction(wxLeft);
    int f = 200;
    for(int i=0; i<DISTORTION_EQ_MAX; i++)
    {
        param.eq[i].type = FilterType::Peak;
        param.eq[i].gain = 0;
        param.eq[i].frequency = f;
        param.eq[i].qfactor = 0.747;
        f += 1200;
    }
    param.freq = 800;
    param.bandwidth = 2;
    param.tone = tone_min;
    param.gain_output = outgain_min;
    param.drive = drive_min;
    param.gain_input = gain_min;
    param.enable = false;
    param_event.SetEventObject(this);

    // wxString str;
    // wxString select_name = attr_name_preset_default;
    // if(DataSave::NodeAttributesGetValue(root_node,attr_name_select,str))
    // {
    //     select_name = str;
    // }
    // else
    // {
    //     DataSave::NodeAttributesSetValue(root_node,attr_name_select,attr_name_preset_default);
    // }
    preset_node = nullptr;
    if(cho_preset->GetCount() > 0)
    {
        preset_node = SelectPreset(cho_preset->GetString(select_index));
    }
}


wxAuiPaneInfo &PanelDistortion::GetPaneInfo()
{
    return paneInfo;
}


void PanelDistortion::SetShow(bool show)
{
    Show(show);
}


void PanelDistortion::OnSliderChange(wxCommandEvent& event)
{
    int id = event.GetId();
    if(id == ID_SLI_TONE)
    {
        wxSlider *sli = wxDynamicCast(FindWindowById(ID_SLI_TONE),wxSlider);
        wxTextCtrl *txt = wxDynamicCast(FindWindowById(ID_TXT_TONE),wxTextCtrl);
        double sv = sli->GetValue();
        double v = tone_min + sv / (1/tone_step);
        txt->SetValue(mDoubleToString(v));
        param.tone = v;
        TrigerEvent(EV_TONE);
    }
    else if(id == ID_SLI_LEVEL)
    {
        wxSlider *sli = wxDynamicCast(FindWindowById(ID_SLI_LEVEL),wxSlider);
        wxTextCtrl *txt = wxDynamicCast(FindWindowById(ID_TXT_LEVEL),wxTextCtrl);
        double sv = sli->GetValue();
        double v = outgain_min + sv / (1/outgain_step);
        txt->SetValue(mDoubleToString(v));
        param.gain_output = v;
        TrigerEvent(EV_POSTGAIN);
    }
    else if(id == ID_SLI_GAIN)
    {
        wxSlider *sli = wxDynamicCast(FindWindowById(ID_SLI_GAIN),wxSlider);
        wxTextCtrl *txt = wxDynamicCast(FindWindowById(ID_TXT_GAIN),wxTextCtrl);
        double sv = sli->GetValue();
        double v = gain_min + sv / (1/gain_step);
        txt->SetValue(mDoubleToString(v));
        param.gain_input = v;
        TrigerEvent(EV_PREGAIN);
    }
    else if(id == ID_SLI_DRIVE)
    {
        wxSlider *sli = wxDynamicCast(FindWindowById(ID_SLI_DRIVE),wxSlider);
        wxTextCtrl *txt = wxDynamicCast(FindWindowById(ID_TXT_DRIVE),wxTextCtrl);
        double sv = sli->GetValue();
        double v = drive_min + sv / (1/drive_step);
        txt->SetValue(mDoubleToString(v));
        param.drive = v;
        TrigerEvent(EV_DRIVE);
    }
    else if(id == ID_SLI_FREQ)
    {
        wxSlider *sli = wxDynamicCast(FindWindowById(ID_SLI_FREQ),wxSlider);
        wxTextCtrl *txt = wxDynamicCast(FindWindowById(ID_TXT_FREQ),wxTextCtrl);
        double sv = sli->GetValue();
        double v = freq_min + sv / (1/freq_step);
        txt->SetValue(mDoubleToString(v));
        param.freq = v;
        TrigerEvent(EV_FREQ);
    }
    else if(id == ID_SLI_WIDTH)
    {
        wxSlider *sli = wxDynamicCast(FindWindowById(ID_SLI_WIDTH),wxSlider);
        wxTextCtrl *txt = wxDynamicCast(FindWindowById(ID_TXT_WIDTH),wxTextCtrl);
        double sv = sli->GetValue();
        double v = bandwidth_min + sv / (1/bandwidth_step);
        txt->SetValue(mDoubleToString(v));
        param.bandwidth = v;
        TrigerEvent(EV_WIDTH);
    }
}

void PanelDistortion::OnTextEnter(wxCommandEvent& event)
{
    int type = event.GetEventType();
    int id = event.GetId();
    if(type == wxEVT_TEXT_ENTER)
    {
        if(id == ID_TXT_TONE)
        {
            wxTextCtrl *txt = wxDynamicCast(FindWindowById(ID_TXT_TONE),wxTextCtrl);
            double v ;
            if(txt->GetValue().ToDouble(&v) == true)
            {
                if((v >= tone_min) && (v <= tone_max))
                {
                    param.tone = v;
                }
            }
            double sv = (param.tone - tone_min) * (1/tone_step);
            wxSlider *sli = wxDynamicCast(FindWindowById(ID_SLI_TONE),wxSlider);
            sli->SetValue(sv);
            TrigerEvent(EV_TONE);
        }
        else if(id == ID_TXT_LEVEL)
        {
            wxTextCtrl *txt = wxDynamicCast(FindWindowById(ID_TXT_LEVEL),wxTextCtrl);
            double v ;
            if(txt->GetValue().ToDouble(&v) == true)
            {
                if((v >= outgain_min) && (v <= outgain_max))
                {
                    param.gain_output = v;
                }
            }
            double sv = (param.gain_output - outgain_min) * (1/outgain_step);
            wxSlider *sli = wxDynamicCast(FindWindowById(ID_SLI_LEVEL),wxSlider);
            sli->SetValue(sv);
            TrigerEvent(EV_POSTGAIN);
        }
        else if(id == ID_TXT_GAIN)
        {
            wxTextCtrl *txt = wxDynamicCast(FindWindowById(ID_TXT_GAIN),wxTextCtrl);
            double v ;
            if(txt->GetValue().ToDouble(&v) == true)
            {
                if((v >= gain_min) && (v <= gain_max))
                {
                    param.gain_input = v;
                }
            }
            double sv = (param.gain_input - gain_min) * (1/gain_step);
            wxSlider *sli = wxDynamicCast(FindWindowById(ID_SLI_GAIN),wxSlider);
            sli->SetValue(sv);
            TrigerEvent(EV_PREGAIN);
        }
        else if(id == ID_TXT_DRIVE)
        {
            wxTextCtrl *txt = wxDynamicCast(FindWindowById(ID_TXT_DRIVE),wxTextCtrl);
            double v ;
            if(txt->GetValue().ToDouble(&v) == true)
            {
                if((v >= drive_min) && (v <= drive_max))
                {
                    param.drive = v;
                }
            }
            double sv = (param.drive - drive_min) * (1/drive_step);
            wxSlider *sli = wxDynamicCast(FindWindowById(ID_SLI_DRIVE),wxSlider);
            sli->SetValue(sv);
            TrigerEvent(EV_DRIVE);
        }
        else if(id == ID_TXT_FREQ)
        {
            wxTextCtrl *txt = wxDynamicCast(FindWindowById(ID_TXT_FREQ),wxTextCtrl);
            double v ;
            if(txt->GetValue().ToDouble(&v) == true)
            {
                if((v >= freq_min) && (v <= freq_max))
                {
                    param.freq = v;
                }
            }
            double sv = (param.freq - freq_min) * (1/freq_step);
            wxSlider *sli = wxDynamicCast(FindWindowById(ID_SLI_FREQ),wxSlider);
            sli->SetValue(sv);
            TrigerEvent(EV_FREQ);
        }
        else if(id == ID_TXT_WIDTH)
        {
            wxTextCtrl *txt = wxDynamicCast(FindWindowById(ID_TXT_WIDTH),wxTextCtrl);
            double v ;
            if(txt->GetValue().ToDouble(&v) == true)
            {
                if((v >= bandwidth_min) && (v <= bandwidth_max))
                {
                    param.bandwidth = v;
                }
            }
            double sv = (param.bandwidth - bandwidth_min) * (1/bandwidth_step);
            wxSlider *sli = wxDynamicCast(FindWindowById(ID_SLI_WIDTH),wxSlider);
            sli->SetValue(sv);
            TrigerEvent(EV_WIDTH);
        }
    }
}

void PanelDistortion::OnChkChange(wxCommandEvent &event)
{
    int id = event.GetId();
    // switch(id)
    {
        if(id == ID_CHK_SWITCH)
        {
            wxCheckBox *chk = wxDynamicCast(FindWindowById(ID_CHK_SWITCH),wxCheckBox);
            param.enable = chk->IsChecked();
            TrigerEvent(EV_ENABLE);
        }
    }
}


void PanelDistortion::OnCombChange(wxCommandEvent& event)
{
    wxChoice *cmb = wxDynamicCast(FindWindowById(ID_CHO_PRESET),wxChoice);
    int i = cmb->GetSelection();
    if((unsigned int)i < cmb->GetCount())
    {
        select_index = i;
        preset_node = SelectPreset(cmb->GetString(i));
        param_event.SetPresetIndex(select_index);
        param_event.SetEventType(myEVT_DISTORTION);
        ProcessWindowEvent(param_event);
    }
}

void PanelDistortion::OnBtnEq(wxCommandEvent& event)
{

    wxDialog dlg(this, wxID_ANY, "Equalizer",wxDefaultPosition,wxSize(600,350),wxDEFAULT_DIALOG_STYLE | wxMAXIMIZE_BOX | wxRESIZE_BORDER);

    equalizer = new GraphicEqualizer(&dlg, wxID_ANY, "Graphic EQ");
    equalizer->SetSampleRate(48000);
    for(int i=0; i<DISTORTION_EQ_MAX; i++)
    {
        equalizer->AddFilter(param.eq[i].type,param.eq[i].frequency,param.eq[i].gain,param.eq[i].qfactor);
    }
    equalizer->Bind(myEVT_EQUALIZER, &PanelDistortion::OnEqualizerEvent, this);
    equalizer->Bind(myEVT_EQUALIZER_FREQUENCY, &PanelDistortion::OnEqualizerFrequencyEvent, this);
    equalizer->Bind(myEVT_EQUALIZER_GAIN, &PanelDistortion::OnEqualizerGainEvent, this);
    equalizer->Bind(myEVT_EQUALIZER_QFACTOR, &PanelDistortion::OnEqualizerQFactorEvent, this);
    equalizer->Bind(myEVT_EQUALIZER_TYPE, &PanelDistortion::OnEqualizerTypeEvent, this);

    dlg.Center();
    dlg.ShowModal();
    delete equalizer;
}

void PanelDistortion::OnEqualizerEvent(MyEventEqualizer &event)
{
    int index = event.GetIndex();
    if((index >= 0) && (index < DISTORTION_EQ_MAX))
    {
        param.eq[index].type = event.GetType();
        param.eq[index].frequency = event.GetFrequency();
        param.eq[index].gain = event.GetGain();
        param.eq[index].qfactor = event.GetQFactor();

        param_event.SetEventType(myEVT_DISTORTION_EQ);
        param_event.SetEqualizerParam(index, param.eq[index]);
        ProcessWindowEvent(param_event);

        // for(int i=0; i<DISTORTION_EQ_MAX; i++)
        {
            wxXmlNode *node_eq = DataSave::FindChildNode(preset_node,wxString::Format("eq-%d",index));
            DataSave::NodeAttributesSetValue(node_eq, attr_name_param_eq_type, filter_type_name[(int)param.eq[index].type]);
            DataSave::NodeAttributesSetValue(node_eq, attr_name_param_eq_freq, mDoubleToString(param.eq[index].frequency).c_str());
            DataSave::NodeAttributesSetValue(node_eq, attr_name_param_eq_gain, mDoubleToString(param.eq[index].gain).c_str());
            DataSave::NodeAttributesSetValue(node_eq, attr_name_param_eq_q, mDoubleToString(param.eq[index].qfactor).c_str());
        }

        // DataSave::NodeAttributesSetValue(preset_node, attr_name_param_eq, mDoubleToString(param.gain_input).c_str());
    }
    event.Skip();
}

void PanelDistortion::OnEqualizerFrequencyEvent(MyEventEqualizer &event)
{
    int index = event.GetIndex();
    if((index >= 0) && (index < DISTORTION_EQ_MAX))
    {
        param.eq[index].frequency = event.GetFrequency();
        param.eq[index].gain = event.GetGain();
        param.eq[index].qfactor = event.GetQFactor();
    }
    event.Skip();
}
void PanelDistortion::OnEqualizerGainEvent(MyEventEqualizer &event)
{
    int index = event.GetIndex();
    if((index >= 0) && (index < DISTORTION_EQ_MAX))
    {
        param.eq[index].gain = event.GetGain();
    }
    event.Skip();
}
void PanelDistortion::OnEqualizerQFactorEvent(MyEventEqualizer &event)
{
    int index = event.GetIndex();
    if((index >= 0) && (index < DISTORTION_EQ_MAX))
    {
        param.eq[index].qfactor = event.GetQFactor();
    }
    event.Skip();
}
void PanelDistortion::OnEqualizerTypeEvent(MyEventEqualizer &event)
{
    int index = event.GetIndex();
    if((index >= 0) && (index < DISTORTION_EQ_MAX))
    {
        param.eq[index].type = event.GetType();
    }
    event.Skip();
}

double PanelDistortion::SetParamTone(double v)
{
    if(v < tone_min)
    {
        v = tone_min;
    }
    else if(v > tone_max)
    {
        v = tone_max;
    }
    double sv = (v - tone_min) * (1/tone_step);
    wxSlider *sli = wxDynamicCast(FindWindowById(ID_SLI_TONE),wxSlider);
    sli->SetValue(sv);
    wxTextCtrl *txt = wxDynamicCast(FindWindowById(ID_TXT_TONE),wxTextCtrl);
    txt->SetValue(mDoubleToString(v));
    param.tone = v;
    param_event.SetTone(v);
    return v;
}

double PanelDistortion::SetParamPostGain(double v)
{
    if(v < outgain_min)
    {
        v = outgain_min;
    }
    else if(v > outgain_max)
    {
        v = outgain_max;
    }
    double sv = (v - outgain_min) * (1/outgain_step);
    wxSlider *sli = wxDynamicCast(FindWindowById(ID_SLI_LEVEL),wxSlider);
    sli->SetValue(sv);
    wxTextCtrl *txt = wxDynamicCast(FindWindowById(ID_TXT_LEVEL),wxTextCtrl);
    txt->SetValue(mDoubleToString(v));
    param.gain_output = v;
    param_event.SetPostGain(v);
    return v;
}

double PanelDistortion::SetParamPreGain(double v)
{
    if(v < gain_min)
    {
        v = gain_min;
    }
    else if(v > gain_max)
    {
        v = gain_max;
    }
    double sv = (v - gain_min) * (1/gain_step);
    wxSlider *sli = wxDynamicCast(FindWindowById(ID_SLI_GAIN),wxSlider);
    sli->SetValue(sv);
    wxTextCtrl *txt = wxDynamicCast(FindWindowById(ID_TXT_GAIN),wxTextCtrl);
    txt->SetValue(mDoubleToString(v));
    param.gain_input = v;
    param_event.SetPreGain(v);
    return v;
}

double PanelDistortion::SetParamDrive(double v)
{
    if(v < drive_min)
    {
        v = drive_min;
    }
    else if(v > drive_max)
    {
        v = drive_max;
    }
    double sv = (v - drive_min) * (1/drive_step);
    wxSlider *sli = wxDynamicCast(FindWindowById(ID_SLI_DRIVE),wxSlider);
    sli->SetValue(sv);
    wxTextCtrl *txt = wxDynamicCast(FindWindowById(ID_TXT_DRIVE),wxTextCtrl);
    txt->SetValue(mDoubleToString(v));
    param.drive = v;
    param_event.SetDrive(v);
    return v;
}


double PanelDistortion::SetParamFreq(double v)
{
    if(v < freq_min)
    {
        v = freq_min;
    }
    else if(v > freq_max)
    {
        v = freq_max;
    }
    double sv = (v - freq_min) * (1/freq_step);
    wxSlider *sli = wxDynamicCast(FindWindowById(ID_SLI_FREQ),wxSlider);
    sli->SetValue(sv);
    wxTextCtrl *txt = wxDynamicCast(FindWindowById(ID_TXT_FREQ),wxTextCtrl);
    txt->SetValue(mDoubleToString(v));
    param.freq = v;
    param_event.SetFreq(v);
    return v;
}

double PanelDistortion::SetParamWidth(double v)
{
    if(v < bandwidth_min)
    {
        v = bandwidth_min;
    }
    else if(v > bandwidth_max)
    {
        v = bandwidth_max;
    }
    double sv = (v - bandwidth_min) * (1/bandwidth_step);
    wxSlider *sli = wxDynamicCast(FindWindowById(ID_SLI_WIDTH),wxSlider);
    sli->SetValue(sv);
    wxTextCtrl *txt = wxDynamicCast(FindWindowById(ID_TXT_WIDTH),wxTextCtrl);
    txt->SetValue(mDoubleToString(v));
    param.bandwidth = v;
    param_event.SetWidth(v);
    return v;
}


bool PanelDistortion::SetParamEnable(bool v)
{
    wxCheckBox *chk = wxDynamicCast(FindWindowById(ID_CHK_SWITCH),wxCheckBox);
    chk->SetValue(v);
    param.enable = v;
    param_event.SetEnable(v);
    return v;
}

double PanelDistortion::GetParamTone() { return param.tone; }
double PanelDistortion::GetParamPostGain() { return param.gain_output; }
double PanelDistortion::GetParamDrive() { return param.drive; }
double PanelDistortion::GetParamPreGain() { return param.gain_input; }
bool PanelDistortion::GetParamEnable() { return param.enable; }
double PanelDistortion::GetParamFreq() { return param.freq; }
double PanelDistortion::GetParamWidth() { return param.bandwidth; }

void PanelDistortion::SetPresetIndex(const unsigned int index)
{
    wxChoice *cmb = wxDynamicCast(FindWindowById(ID_CHO_PRESET),wxChoice);
    if(index < cmb->GetCount())
    {
        select_index = index;
        param_event.SetPresetIndex(select_index);
        cmb->SetSelection(index);
        preset_node = SelectPreset(cmb->GetString(index));
    }
}

int PanelDistortion::GetPresetIndex()
{
    return select_index;
}

void PanelDistortion::SetParamEq(int band,FilterParam &eq)
{
    if(band < DISTORTION_EQ_MAX)
    {
        param.eq[band] = eq;
    }
}


void PanelDistortion::TrigerEvent(int ev)
{
    switch(ev)
    {
        case EV_TONE:
        {
            param_event.SetEventType(myEVT_DISTORTION_TONE);
            param_event.SetTone(param.tone);
            ProcessWindowEvent(param_event);
            DataSave::NodeAttributesSetValue(preset_node, attr_name_param_tone, mDoubleToString(param.tone).c_str());
        }
        break;
        case EV_POSTGAIN:
        {
            param_event.SetEventType(myEVT_DISTORTION_LEVEL);
            param_event.SetPostGain(param.gain_output);
            ProcessWindowEvent(param_event);
            DataSave::NodeAttributesSetValue(preset_node, attr_name_param_postgain, mDoubleToString(param.gain_output).c_str());
        }
        break;
        case EV_PREGAIN:
        {
            param_event.SetEventType(myEVT_DISTORTION_GAIN);
            param_event.SetPreGain(param.gain_input);
            ProcessWindowEvent(param_event);
            DataSave::NodeAttributesSetValue(preset_node, attr_name_param_pregain, mDoubleToString(param.gain_input).c_str());
        }
        break;
        case EV_DRIVE:
        {
            param_event.SetEventType(myEVT_DISTORTION_DRIVE);
            param_event.SetDrive(param.drive);
            ProcessWindowEvent(param_event);
            DataSave::NodeAttributesSetValue(preset_node, attr_name_param_drive, mDoubleToString(param.drive).c_str());
        }
        break;
        case EV_FREQ:
        {
            param_event.SetEventType(myEVT_DISTORTION_FREQ);
            param_event.SetFreq(param.freq);
            ProcessWindowEvent(param_event);
            DataSave::NodeAttributesSetValue(preset_node, attr_name_param_freq, mDoubleToString(param.freq).c_str());
        }
        break;
        case EV_WIDTH:
        {
            param_event.SetEventType(myEVT_DISTORTION_WIDTH);
            param_event.SetWidth(param.bandwidth);
            ProcessWindowEvent(param_event);
            DataSave::NodeAttributesSetValue(preset_node, attr_name_param_bandwidth, mDoubleToString(param.bandwidth).c_str());
        }
        break;
        case EV_ENABLE:
        {
            param_event.SetEventType(myEVT_DISTORTION_ENABLE);
            param_event.SetEnable(param.enable);
            ProcessWindowEvent(param_event);
            DataSave::NodeAttributesSetValue(preset_node, attr_name_param_enable, param.enable ? "1" : "0");
        }
        break;
    }
}


wxXmlNode *PanelDistortion::SelectPreset(const wxString name)
{
    double tone = param.tone;
    double gain_output = param.gain_output;
    double drive = param.drive;
    double gain_input = param.gain_input;
    bool enable = param.enable;
    double freq = param.freq;
    double bandwidth = param.bandwidth;

    wxString str;
    wxXmlNode *child;
    child = root_node->GetChildren();
    while(child)
    {
        if(strcmp(child->GetName().c_str(), name.c_str()) == 0)
        {
            break;
        }
        child = child->GetNext();
    }

    if(DataSave::NodeAttributesGetValue(child,attr_name_param_enable,str))
    {
        int v ;
        if(str.ToInt(&v))
        {
            enable = v > 0 ? true : false;
        }
    }

    if(DataSave::NodeAttributesGetValue(child, attr_name_param_tone, str))
    {
        double v;
        if(str.ToDouble(&v))
        {
            tone = v;
        }
    }

    if(DataSave::NodeAttributesGetValue(child, attr_name_param_postgain, str))
    {
        double v;
        if(str.ToDouble(&v))
        {
            gain_output = v;
        }
    }

    if(DataSave::NodeAttributesGetValue(child, attr_name_param_drive, str))
    {
        double v;
        if(str.ToDouble(&v))
        {
            drive = v;
        }
    }

    if(DataSave::NodeAttributesGetValue(child, attr_name_param_pregain, str))
    {
        double v;
        if(str.ToDouble(&v))
        {
            gain_input = v;
        }
    }

    if(DataSave::NodeAttributesGetValue(child, attr_name_param_freq, str))
    {
        double v;
        if(str.ToDouble(&v))
        {
            freq = v;
        }
    }

    if(DataSave::NodeAttributesGetValue(child, attr_name_param_bandwidth, str))
    {
        double v;
        if(str.ToDouble(&v))
        {
            bandwidth = v;
        }
    }

    for(int i=0; i<DISTORTION_EQ_MAX; i++)
    {
        wxXmlNode *node_eq = DataSave::FindChildNode(child,wxString::Format("eq-%d",i));
        if(DataSave::NodeAttributesGetValue(node_eq, attr_name_param_eq_type, str))
        {
            int v;
            if(str.ToInt(&v))
            {
                param.eq[i].type = (FilterType)v;
            }
        }

        if(DataSave::NodeAttributesGetValue(node_eq, attr_name_param_eq_freq, str))
        {
            double v;
            if(str.ToDouble(&v))
            {
                param.eq[i].frequency = v;
            }
        }

        if(DataSave::NodeAttributesGetValue(node_eq, attr_name_param_eq_gain, str))
        {
            double v;
            if(str.ToDouble(&v))
            {
                param.eq[i].gain = v;
            }
        }

        if(DataSave::NodeAttributesGetValue(node_eq, attr_name_param_eq_q, str))
        {
            double v;
            if(str.ToDouble(&v))
            {
                param.eq[i].qfactor = v;
            }
        }
    }


    SetParamEnable(enable);
    SetParamTone(tone);
    SetParamPostGain(gain_output);
    SetParamDrive(drive);
    SetParamPreGain(gain_input);
    SetParamFreq(freq);
    SetParamWidth(bandwidth);

    // if(child == NULL)
    // {
    //     child = new wxXmlNode(wxXML_ELEMENT_NODE,name);
    //     WriteToXML(child);
    //     root_node->AddChild(child);
    // }
    return child;
}

void PanelDistortion::PresetListClear(void)
{
    wxChoice *cmb = wxDynamicCast(FindWindowById(ID_CHO_PRESET),wxChoice);
    if(cmb)
    {
        cmb->Clear();
        preset_node = nullptr;
    }
}

void PanelDistortion::AddPresetList(const wxString &preset_name)
{
    wxChoice *cmb = wxDynamicCast(FindWindowById(ID_CHO_PRESET),wxChoice);
    if(cmb)
    {
        cmb->Append(preset_name);
    }
}


wxXmlNode *PanelDistortion::SaveCurrentParamsToNewPreset(wxXmlNode *root, const wxString &new_preset_name,int &is_same)
{
    wxXmlNode *child = nullptr;
    is_same = 0;
    if((root != nullptr) && (new_preset_name.empty() == false))
    {
        //查找有没有名字相同的预设
        child = root->GetChildren();
        while(child)
        {
            if(strcmp(child->GetName().c_str(), new_preset_name.c_str()) == 0)
            {
                is_same = 1;
                return nullptr;
            }
            child = child->GetNext();
        }
        child = new wxXmlNode(wxXML_ELEMENT_NODE,new_preset_name);
        WriteToXML(child);
        root->AddChild(child);
        wxChoice *cmb = wxDynamicCast(FindWindowById(ID_CHO_PRESET),wxChoice);
        if(cmb)
        {
            cmb->Append(new_preset_name);
        }
    }
    return child;
}

bool PanelDistortion::WriteToXML(wxXmlNode *node)
{
    wxXmlNode *node_eq;
    if(node)
    {
        DataSave::NodeAttributesSetValue(node, attr_name_param_enable, param.enable ? "1" : "0");
        DataSave::NodeAttributesSetValue(node, attr_name_param_drive, mDoubleToString(param.drive).c_str());
        DataSave::NodeAttributesSetValue(node, attr_name_param_postgain, mDoubleToString(param.gain_output).c_str());
        DataSave::NodeAttributesSetValue(node, attr_name_param_tone, mDoubleToString(param.tone).c_str());
        DataSave::NodeAttributesSetValue(node, attr_name_param_pregain, mDoubleToString(param.gain_input).c_str());
        DataSave::NodeAttributesSetValue(node, attr_name_param_freq, mDoubleToString(param.freq).c_str());
        DataSave::NodeAttributesSetValue(node, attr_name_param_bandwidth, mDoubleToString(param.bandwidth).c_str());
        {
            for(int i=0; i<DISTORTION_EQ_MAX; i++)
            {
                node_eq = DataSave::FindChildNode(node,wxString::Format("eq-%d",i));
                DataSave::NodeAttributesSetValue(node_eq, attr_name_param_eq_type, filter_type_name[(int)param.eq[i].type]);
                DataSave::NodeAttributesSetValue(node_eq, attr_name_param_eq_freq, mDoubleToString(param.eq[i].frequency).c_str());
                DataSave::NodeAttributesSetValue(node_eq, attr_name_param_eq_gain, mDoubleToString(param.eq[i].gain).c_str());
                DataSave::NodeAttributesSetValue(node_eq, attr_name_param_eq_q, mDoubleToString(param.eq[i].qfactor).c_str());
            }
        }
        return true;
    }
    return false;
}